package com.zhanglijie.base.volatileLearn;

import java.util.concurrent.CountDownLatch;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/5/15 0015 22:34
 * 通过cachline的时空效应可以看出cacheline能带来一些好处，但是这个只能用于
 * 单线程单个变量或者单个数组。在多个线程下 如果多个变量在同一cacheline中这个是不好的
 * 一旦某个线程修改了(xy)中的x,另外一个线程虽然要改y即使这个y在本线程cpu缓存中但已经失效了根据
 * mesi协议。所以要修改y要重新读取（xy）的cacheline。这个就是cacheline带来的为共享问题，所以解决方办法就是认为填充解决。
 * 引用对象除外因为引用对象分配在堆中,堆中分配内存比较随机打散不会想obj基本类型靠在一块。
 * 如果 引用类型在一个thread中循环创建for(i-100){new obj}这个会导致堆钟指针会碰撞使用，为此tlab产生
 * 每个线程都分配自己操作堆中对象的指针，降低指针碰撞
 * 伪共享问题 的解决是空间换取时间 牺牲空间换取时间
 *
 *
 */
public class CachelineProblems {
    public static void main(String[] args) throws InterruptedException {
        long start = System.currentTimeMillis();
        Count count = new Count();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000000000; i++) {
                count.a++;
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000000000; i++) {
                count.b++;
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(System.currentTimeMillis()-start);

    }
    //方式一 手动写变量填充
    static class Count{
            volatile  long a;
        //人为填充  有些博客说要public 这个private也是可以的
        private long c,d,e,f,g,h,i; //36754(no padding) vs 11802(pading)
            volatile  long b;

    }

    //方式二  注解填充（底层和方式一一致）
    static class Count2{

        volatile long a;
        @sun.misc.Contended //这个要加-XX:-RestrictContented  jdk11  @jdk.internal.misc.Contented
        volatile long b;
    }
    //方式三 层级填充（底层和方式一一致）
    static class A{
        volatile  long a;
    }
    static class B extends A{
        int a2,a3,a4,a5,a6,a7,a8;
    }
    static class C extends B{
        volatile long b;
    }

}
